<script setup>
import { getProcessor } from 'bytemd'

const props = defineProps({
  markdownContent: {
    type: String,
    required: true,
  },
  containerSelector: {
    type: String,
    default: '.markdown-body',
  },
})

// 目录树数据
const tocTree = ref([])
const currentNodeKey = ref('')
const containerElement = ref(null)

// 解析Markdown生成目录树
function parseToc() {
  // 使用 ref 保存扁平化标题列表
  const flatHeadings = ref([])

  // 改进的文本提取
  const extractText = (node) => {
    if (node.type === 'text')
      return node.value
    if (node.type === 'element' && node.tagName === 'img')
      return node.properties?.alt || ''
    if (node.type === 'comment' || node.tagName === 'code')
      return ''
    return (node.children || []).map(extractText).join('')
  }

  getProcessor({
    plugins: [
      {
        rehype: p =>
          p.use(() => (tree) => {
            if (!tree?.children)
              return

            // 清空旧数据
            flatHeadings.value = []

            const walk = (nodes) => {
              nodes.forEach((node) => {
                if (node.type === 'element' && /^h[1-6]$/.test(node.tagName)) {
                  flatHeadings.value.push({
                    level: Number.parseInt(node.tagName.substring(1)),
                    text: extractText(node).trim(),
                    tagName: node.tagName,
                    // 统一使用索引作为ID前缀
                    id: `heading-${flatHeadings.value.length}`,
                  })
                }
                if (node.children)
                  walk(node.children)
              })
            }

            walk(tree.children)
          }),
      },
    ],
  }).processSync(props.markdownContent)

  // 构建嵌套树
  tocTree.value = buildTree(flatHeadings.value)

  // 等待DOM更新后设置ID
  nextTick(() => {
    setHeadingIds(flatHeadings.value)
  })
}

// 统一的ID设置方法
function setHeadingIds(headings) {
  const container
    = containerElement.value || document.querySelector(props.containerSelector)
  if (!container)
    return

  // 获取实际DOM中的标题元素
  const domHeadings = Array.from(
    container.querySelectorAll('h1, h2, h3, h4, h5, h6'),
  )

  // 确保数量和顺序匹配
  if (domHeadings.length !== headings.length) {
    console.warn('标题数量不匹配，可能渲染未完成')
    return
  }

  // 统一设置ID
  domHeadings.forEach((heading, index) => {
    heading.id = headings[index].id // 使用parseToc中生成的相同ID
  })
}

// 构建树形结构
function buildTree(headings, currentLevel = 1) {
  const result = []
  let i = 0

  while (i < headings.length) {
    const heading = headings[i]

    if (heading.level === currentLevel) {
      const node = { ...heading, children: [] }
      result.push(node)
      i++

      const nextHeadings = headings.slice(i)
      if (nextHeadings.length && nextHeadings[0].level > currentLevel) {
        node.children = buildTree(nextHeadings, currentLevel + 1)
        i += node.children.length
      }
    }
    else if (heading.level < currentLevel) {
      break
    }
    else {
      i++
    }
  }

  return result
}

// 处理节点点击
function handleNodeClick(data) {
  currentNodeKey.value = data.id
  const element = document.getElementById(data.id)
  if (element) {
    element.scrollIntoView({ behavior: 'smooth' })
  }
}

// 监听Markdown内容变化
watch(() => props.markdownContent, parseToc, { immediate: true })

const treeProps = {
  children: 'children',
  label: 'text',
}
</script>

<template>
  <AppCard bordered class="h-300 w-full flex-col border-rd-5 p-10 us">
    <div class="mb-5 h-38 border-b font-size-18 fw-light">
      目录
    </div>
    <el-scrollbar>
      <el-tree
        :data="tocTree"
        :props="treeProps"
        node-key="id"
        default-expand-all
        :highlight-current="true"
        :expand-on-click-node="false"
        :current-node-key="currentNodeKey"
        @node-click="handleNodeClick"
      >
        <template #default="{ node }">
          <span>
            {{ node.label }}
          </span>
        </template>
      </el-tree>
    </el-scrollbar>
  </AppCard>
</template>

<style scoped>
:deep(.el-tree-node__expand-icon) {
  display: none;
}

:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
  background-color: var(--el-color-primary-light-9);
  color: var(--el-color-primary);
}
</style>
